---
id: generichost
title: 通用主机
---

import Tabs from "@theme/Tabs";
import TabItem from "@theme/TabItem";
import BilibiliCard from '@site/src/components/BilibiliCard.js';

### 定义

命名空间：TouchSocket.Hosting <br/>
程序集：[TouchSocket.Hosting.dll](https://www.nuget.org/packages/TouchSocket.Hosting)<br/>
程序集：[TouchSocketPro.Hosting.dll](https://www.nuget.org/packages/TouchSocketPro.Hosting)


## 一、说明

`Hosting`通用主机，是在创建一个[HostBuilder](https://learn.microsoft.com/zh-cn/dotnet/core/extensions/generic-host) 之后，可以通过Add的服务的形式创建`TouchSocket`的一些组件。如`TcpService`、`TcpClient`、`NamedPipeService`、`NamedPipeclient`等。

<BilibiliCard title="为什么要用通用主机服务" link="https://www.bilibili.com/cheese/play/ep1564632" isPro="true"/>

## 二、安装Nuget包

在安装`Nuget`之前，最好先确认目标项目是一个主机项目。例如：[辅助角色服务模板](https://learn.microsoft.com/zh-cn/dotnet/core/extensions/generic-host)、 [AspNetCore](https://learn.microsoft.com/zh-cn/aspnet/core)等。如果是其他项目，请自行解决依赖。

使用`Nuget`安装`TouchSocket.Hosting`、`TouchSocketPro.Hosting`、`TouchSocket.AspNetCore`、`TouchSocketPro.AspNetCore`其中的**任意一个**。

:::info 备注

`TouchSocket.Hosting`、`TouchSocketPro.Hosting`、`TouchSocket.AspNetCore`、`TouchSocketPro.AspNetCore`都可以安装使用。主要区别就是：Hosting的只包含基础扩展。AspNetCore的会对Web项目有更多扩展。

:::  

:::tip 建议

一般建议`Web`项目使用`TouchSocket.AspNetCore`、`TouchSocketPro.AspNetCore`。辅助角色项目、`MAUI`项目等使用`TouchSocket.Hosting`、`TouchSocketPro.Hosting`。

:::  

## 三、添加服务器类

一些常用的服务器组件，都已经被封装了，可以直接使用。例如：

- TcpService
- UdpService
- TcpDmtpService（由TouchSocket.AspNetCore提供）

:::info 备注

没被封装的组件只是没直接提供扩展方法，而不是不能使用。具体操作请看下文。

:::  

### 3.1 在Aspnetcore中添加

下列示例只配置了监听端口，更多配置请看[TcpService](./tcpservice.mdx)。

```csharp {7-12} showLineNumbers
public static void Main(string[] args)
{
    var builder = WebApplication.CreateBuilder(args);

    ...

    #region 添加Tcp服务器
    builder.Services.AddTcpService(config =>
    {
        config.SetListenIPHosts(7789);
    });
    #endregion

    var app = builder.Build();

    ...

    app.Run();
}
```

### 3.2 在辅助角色项目中添加

辅助角色项目、MAUI项目等使用`TouchSocket.Hosting`、`TouchSocketPro.Hosting`。

<Tabs
    defaultValue="tab1"
    values=
    {[
        { label: "NET6.0",value: "tab1"},
        { label: "NET8.0+", value: "tab2" }
    ]}
>
<TabItem value="tab1">

```csharp {6-11} showLineNumbers
public static void Main(string[] args)
{
    IHost host = Host.CreateDefaultBuilder(args)
        .ConfigureServices(services =>
        {
            #region 添加Tcp服务器
            services.AddTcpService(config =>
            {
                config.SetListenIPHosts(7789);
            });
            #endregion
            services.AddHostedService<Worker>();
        })
        .Build();

    host.Run();
}
```

</TabItem>
<TabItem value="tab2">

```csharp {5-10} showLineNumbers
public static void Main(string[] args)
{
    var builder = Host.CreateApplicationBuilder(args);
    builder.Services.AddHostedService<Worker>();
    #region 添加Tcp服务器
    builder.Services.AddTcpService(config =>
    {
        config.SetListenIPHosts(7789);
    });
    #endregion
    var host = builder.Build();
    host.Run();
}

```
</TabItem>
</Tabs>

<BilibiliCard title="认识通用主机服务" link="https://www.bilibili.com/cheese/play/ep1564639" isPro="true"/>

### 3.3 添加自定义服务器

通过上述的方式添加的服务器，会使用固定的接口作为注册类型。例如：通过默认的`AddTcpService`来添加服务器，则会使用`ITcpService`作为注册类型。

所以当想要添加两个服务器时，由于容器问题，第二个就会把第一个覆盖掉。所以就需要重新实现一个`ITcpService`接口，来添加自定义的服务器。

例如：

我们可以先需要声明一个接口`IMyTcpService`，继承自`ITcpService`接口，然后声明自定义类`MyTcpService`，继承`TcpService`，同时实现`IMyTcpService`。

```csharp showLineNumbers
class MyTcpService : TcpService, IMyTcpService
{

}

interface IMyTcpService : ITcpService
{

}
```

然后调用`AddTcpService`泛型注册即可。

```csharp showLineNumbers
services.AddTcpService<IMyTcpService, MyTcpService>(config =>
{
    config.SetListenIPHosts(7790);
});
```

:::info 备注

这里可以使用`AddTcpService`泛型注册的原因是`MyTcpService`是`TcpService`的派生类。如果不是，则需要使用`AddServiceHostedService`来注册。

:::  

### 3.4 添加其他生命周期的服务

默认情况下，框架内提供的所有IService类的注册服务（即：`AddServiceHostedService`），都是单例注册。且生命周期跟随整个Host。当Host启动时，所有注册的服务都会被创建。并且也会调用Start。当Host关闭时，所有注册的服务都会被销毁（当然可以提前注销，但是无法控制Start）。

但有的时候，我们需要将一个服务注册为瞬态，然后自己完全管理生命周期。那么我们可以通过下列方式来实现。

- AddSingletonSetupConfigObject：单例
- AddTransientSetupConfigObject：瞬态
- AddScopedSetupConfigObject：区域

```csharp {6-11} showLineNumbers
public static void Main(string[] args)
{
    IHost host = Host.CreateDefaultBuilder(args)
        .ConfigureServices(services =>
        {
            //添加瞬态Tcp服务器。
            //瞬态服务器，在host启动时，不会自己start，需要手动调用
            services.AddTransientSetupConfigObject<ITcpService,TcpService>(config =>
            {
                config.SetListenIPHosts(7789);
            });
            services.AddHostedService<Worker>();
        })
        .Build();

    host.Run();
}
```

:::tip 提示

通过这三中方式直接注册的服务，在Host启动时，不会自动调用Start。所以需要自己手动调用。

:::  

<BilibiliCard title="为什么需要DI容器" link="https://www.bilibili.com/cheese/play/ep1564640" isPro="true"/>
<BilibiliCard title="使用IServiceCollection以及3种生命周期" link="https://www.bilibili.com/cheese/play/ep1564651" isPro="true"/>

## 四、添加客户端类

一些常用的客户端组件，都已经被封装了，可以直接使用。例如：

- TcpClient
- TcpDmtpClient（由TouchSocket.AspNetCore提供）

:::info 备注

没被封装的组件只是没直接提供扩展方法，而不是不能使用。具体操作请看下文。

:::  

### 4.1 添加TcpClient

客户端类的添加，和上面服务类的添加，基本一致。只不过默认就区分了瞬态、单例等注册方式。

```csharp {6-9} showLineNumbers
public static void Main(string[] args)
{
    IHost host = Host.CreateDefaultBuilder(args)
        .ConfigureServices(services =>
        {
            services.AddTransientTcpClient(config =>
            {
                config.SetRemoteIPHost("127.0.0.1:7789");
            });

            services.AddHostedService<Worker>();
        })
        .Build();

    host.Run();
}
```

:::tip 提示

客户端类的服务，在Host启动时，不会自动调用Connect。所以需要自己手动调用。

:::  


## 五、添加没有预设的服务

实际上所有的组件，都可以通过下列方法注册：

- AddSingletonSetupConfigObject：单例
- AddTransientSetupConfigObject：瞬态
- AddScopedSetupConfigObject：区域

但是对于服务器类的，可以根据其继承类，来选择更贴切的服务器注册。这样就不用自己管理生命周期。

例如：对于TcpDmtpService。他是继承自TcpService，所以也可以直接使用AddTcpService**泛型**来注册。

```csharp {6-9} showLineNumbers
public static void Main(string[] args)
{
    IHost host = Host.CreateDefaultBuilder(args)
        .ConfigureServices(services =>
        {
            services.AddTcpService<ITcpDmtpService, TcpDmtpService>(config => 
            {
                config.SetListenIPHosts(8848);
            });
        })
        .Build();

    host.Run();
}
```

## 六、选项模式配置服务器

通过选项模式，可以方便的对服务器进行配置。

<BilibiliCard title="选项模式配置服务器" link="https://www.bilibili.com/cheese/play/ep1581737" isPro="true"/>


## 七、实战

<BilibiliCard title="使用通用主机的方式改造BigDogServer(1)" link="https://www.bilibili.com/cheese/play/ep1564652" isPro="true"/>
<BilibiliCard title="使用通用主机的方式改造BigDogServer(2)" link="https://www.bilibili.com/cheese/play/ep1564653" isPro="true"/>
<BilibiliCard title="使用通用主机的方式改造BigDogServer(3)" link="https://www.bilibili.com/cheese/play/ep1564665" isPro="true"/>
<BilibiliCard title="完成通用主机改造BigDogServer" link="https://www.bilibili.com/cheese/play/ep1564666" isPro="true"/>
<BilibiliCard title="使用NLog进行日志记录" link="https://www.bilibili.com/cheese/play/ep1581739" isPro="true"/>

## 八、部署

### 8.1 部署到Windows

<BilibiliCard title="以Windows服务发布运行" link="https://www.bilibili.com/cheese/play/ep1581740" isPro="true"/>
<BilibiliCard title="使用AOT发布Window服务" link="https://www.bilibili.com/cheese/play/ep1581742" isPro="true"/>
<BilibiliCard title="解决AOT下的Json序列化问题" link="https://www.bilibili.com/cheese/play/ep1581747" isPro="true"/>

###  8.2 部署到Linux

<BilibiliCard title="发布到Linux并（长久）运行" link="https://www.bilibili.com/cheese/play/ep1581750" isPro="true"/>
<BilibiliCard title="使用Systemed发布到linux" link="https://www.bilibili.com/cheese/play/ep1581762" isPro="true"/>

###  8.3 部署到Docker

<BilibiliCard title="创建Dockerfile和改造项目" link="https://www.bilibili.com/cheese/play/ep1581766" isPro="true"/>
<BilibiliCard title="以Docker部署运行主机服务" link="https://www.bilibili.com/cheese/play/ep1581767" isPro="true"/>


[本文示例Demo](https://gitee.com/RRQM_Home/TouchSocket/tree/master/examples_host/Examples.Host)